#ifndef __LOG_FORMAT_H__
#define __LOG_FORMAT_H__

#include <vector>
#include <cassert>
#include <sstream>
#include "log_message.hpp"
#include "../util/handlerMessage.hpp"

// 多态实现格式化输出单个子要素 -> 易扩展
// 格式化器实现完整输出子要素 -> 解析格式化字符串并按照顺序把子要素对象暂存到数组中统一遍历输出

namespace log_system
{
    // 各要素格式化基类
    class FormatElement
    {
    public:
        using pointer = std::shared_ptr<FormatElement>;
        virtual void format(std::ostream &out, const log_system::LogMessage &message) = 0;
    }; // class FormatElement

    // 要素派生类: 等级要素、时间要素、源文件名称要素、源文件行号要素、线程ID要素、日志器要素、有效载荷信息要素、制表符要素、换行要素、 其他要素
    class LevelFormatElement : public FormatElement
    {
    public:
        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << log_system::LogLevel::levelTransform(message._level);
        }
    }; // class LevelFormatElement

    class TimeFormatElement : public FormatElement
    {
    public:
        TimeFormatElement(const std::string &time_format = "%H:%M:%S")
            : _time_format(time_format) {}

        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            struct tm st;
            localtime_r(&message._time, &st);
            char buffer[32] = {0};
            strftime(buffer, sizeof(buffer) - 1, _time_format.c_str(), &st);
            out << buffer;
        }

    private:
        std::string _time_format;
    }; // class TimeFormatElement

    class FileFormatElement : public FormatElement
    {
    public:
        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << message._file;
        }
    }; // class FileFormatElement

    class LineFormatElement : public FormatElement
    {
    public:
        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << message._line;
        }
    }; // class LineFormatElement

    class ThreadIDFormatElement : public FormatElement
    {
    public:
        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << message._threadID;
        }
    }; // class ThreadIDFormatElement

    class LoggerFormatElement : public FormatElement
    {
    public:
        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << message._logger;
        }
    }; // class LoggerFormatElement

    class PayloadFormatElement : public FormatElement
    {
    public:
        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << message._payload;
        }
    }; // class PayloadFormatElement

    class TabFormatElement : public FormatElement
    {
    public:
        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << "\t";
        }
    }; // class TabFormatElement

    class NewLineFormatElement : public FormatElement
    {
    public:
        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << "\n";
        }
    }; // class NewLineFormatElement

    class OtherFormatElement : public FormatElement
    {
    public:
        OtherFormatElement(const std::string &str)
            : _str(str) {}

        void format(std::ostream &out, const log_system::LogMessage &message) override
        {
            out << _str;
        }

    private:
        std::string _str;
    }; // class OtherFormatElement

    // -----------------------------------------------------------------------------------------------

    /*
     * %p：日志级别 %d：日期 包含{%H:%M:%S} %f：源文件名称  %l：源文件行号
     * %t：线程ID * %c：日志器名称 %T：缩进  %m：有效载荷信息  %n：换行
     */

    // 格式化输出顺序: 日志等级、时间、源文件名称、源代码行号、线程ID、日志器名称、有效载荷信息

    // 格式化日志器
    // 格式化到ostream输出流中
    class Formatter
    {
    public:
        using pointer = std::shared_ptr<Formatter>;

    public:
        Formatter(const std::string &pattern = "[%p][%d{%H:%M:%S}][%f:%l][%t][%c]%T%m%n")
            : _pattern(pattern)
        {
            assert(parsePattern()); // 调用构造函数解析格式化规则字符串_pattern ->
        }

        void format(std::ostream &out, log_system::LogMessage &message) // 对message格式化
        {
            for (auto &element : _elements)
            {
                element->format(out, message);
            }
        }

        std::string format(log_system::LogMessage &message)
        {
            std::stringstream ss;
            format(ss, message);
            return ss.str();
        }

    private:
        inline bool parsePattern(); // 对pattern解析

        // 不同格式化字符创建格式化要素子项
        FormatElement::pointer createElement(const std::string &format_character, const std::string &extra_parameter);

    private:
        std::string _pattern;                          // 格式化规则字符串
        std::vector<FormatElement::pointer> _elements; // 子要素对象数组
    };

    // [%p][%d{%H:%M:%S}][%f:%l][%t][%c]%T%m%n
    // 1. 没有以%为起始的字符串是原始字符串，遇到%代表原始字符串结束位置
    // 2. %后紧跟字符是不是%，是则是%字符，不是则是格式化字符
    // 3. 紧跟格式化字符之后有没有{，如果有则是子格式
    inline bool Formatter::parsePattern()
    {
        // std::cout << "_pattern : " << _pattern.c_str() << std::endl;
        std::vector<std::pair<std::string, std::string>> elements_buffer; // vector<格式化字符, 额外参数/原始字符>(暂存子要素的数组)
        size_t position = 0;
        std::string extra_parameter;  // 额外参数
        std::string format_character; // 格式化字符
        while (position < _pattern.size())
        {
            if (_pattern[position] != '%') // 原始字符串处理
            {
                extra_parameter.push_back(_pattern[position]);
                position++;
                continue;
            }

            // 原始字符串处理完毕！！！

            if (_pattern[position + 1] == '%' && position + 1 < _pattern.size()) // 双%处理
            {
                extra_parameter.push_back('%');
                position += 2;
                continue;
            }

            // 原始字符串添加到格式化列表中！！！
            if (!extra_parameter.empty())
            {
                elements_buffer.push_back(std::make_pair("", extra_parameter));
                extra_parameter.clear();
            }

            position += 1;
            if (position == _pattern.size())
            {
                HandlerMessage::handlerMessage(log_system::HandlerMessage::HandlerLevel::INFO, "log-system/include/log/log_format.hpp", __LINE__, "do not have format character after \% character ");
                return false;
            }
            format_character = _pattern[position]; // 格式化字符处理
            position += 1;

            if (position < _pattern.size() && _pattern[position] == '{') // 子格式处理
            {
                position += 1;
                while (position < _pattern.size() && _pattern[position] != '}')
                {
                    extra_parameter.push_back(_pattern[position]);
                    position++;
                }
                if (position == _pattern.size()) // 并没有遇到'}'
                {
                    HandlerMessage::handlerMessage(log_system::HandlerMessage::HandlerLevel::INFO, "log-system/include/log/log_format.hpp", __LINE__, "{} child format is not matching");
                    return false;
                }
                position += 1;
            }

            elements_buffer.push_back(std::make_pair(format_character, extra_parameter)); // 格式化字符添加到暂存子要素数组中！！！
            format_character.clear();
            extra_parameter.clear();
        }
        if (position == _pattern.size() && !extra_parameter.empty())
        {
            elements_buffer.push_back(std::make_pair(format_character, extra_parameter));
        }

        for (auto &x : elements_buffer) // 添加到子要素对象数组_elements中！！！
        {
            // std::cout << x.first << " " << x.second << std::endl;
            _elements.push_back(createElement(x.first, x.second));
        }
        return true;
    }

    // 为什么需要指针？使用指针调用构成多态, 可构建派生类对象并指向派生类完成对应格式化字符输出对应格式化数据
    FormatElement::pointer Formatter::createElement(const std::string &format_character, const std::string &extra_parameter)
    {
        if (format_character == "d")
            return std::make_shared<TimeFormatElement>(extra_parameter);
        else if (format_character == "t")
            return std::make_shared<ThreadIDFormatElement>();
        else if (format_character == "c")
            return std::make_shared<LoggerFormatElement>();
        else if (format_character == "f")
            return std::make_shared<FileFormatElement>();
        else if (format_character == "l")
            return std::make_shared<LineFormatElement>();
        else if (format_character == "p")
            return std::make_shared<LevelFormatElement>();
        else if (format_character == "T")
            return std::make_shared<TabFormatElement>();
        else if (format_character == "m")
            return std::make_shared<PayloadFormatElement>();
        else if (format_character == "n")
            return std::make_shared<NewLineFormatElement>();

        if (format_character.empty())
            return std::make_shared<OtherFormatElement>(extra_parameter);

        HandlerMessage::handlerMessage(log_system::HandlerMessage::HandlerLevel::INFO, "log-system/include/log/log_format.hpp", __LINE__, "There is no corresponding format character in the format string rule !!! format charater : %s", format_character.c_str());
        exit(-1);
        return FormatElement::pointer();
    }

} // namespace log_system

#endif // #ifndef __LOG_FORMAT_H__
